package org.gpp.proj1.camera;

import java.util.LinkedList;
import java.util.List;

import org.gpp.proj1.camera.action.CameraAction;

import com.jme.math.Vector3f;
import com.jme.scene.CameraNode;
import com.jme.scene.Node;

/**
 * Class that handles the game's camera, executing
 * camera actions (look at, move to, etc) and focusing
 * on selected objects
 * 
 * @author Paolo Victor, paolovictor@gmail.com
 */
public class CameraDirector {
	protected List<CameraAction> actionsQueue;
	
	protected CameraAction currentAction;

	protected CameraNode camera;
	
	protected Node focusedObject;

	/**
	 * Default constructor
	 */
	public CameraDirector( CameraNode camera ) {
		assert camera != null : "Cannot create a director with a null camera node";		
		
		this.camera = camera;
		this.focusedObject = null;
		this.currentAction = null;
		this.actionsQueue = new LinkedList<CameraAction>();
	}
	
	/**
	 * Protected constructor, used for testing purposes
	 */
	protected CameraDirector( CameraNode camera, List<CameraAction> actionsQueue ) {
		this.camera = camera;
		this.focusedObject = null;
		this.currentAction = null;
		this.actionsQueue = actionsQueue;
	}

	/**
	 * Updates the camera. If there's a current unfinished action, updates it,
	 * otherwise fetchs a new action from the queue
	 * 
	 * @param timePerFrame
	 */
	public void updateCamera( float timePerFrame ) {
		// Updates action
		if( currentAction == null ) {
			if( ! actionsQueue.isEmpty() ) {
				currentAction = actionsQueue.remove( 0 );
			}
		}
		
		if( currentAction != null ) {
			if( currentAction.isFinished() ) {
				if( ! actionsQueue.isEmpty() ) {
					currentAction = actionsQueue.remove( 0 );
				} else {
					currentAction = null;
				}
			} else {
				currentAction.updateAction( timePerFrame, camera );
			}
		} 
		
		// Look at the focused object, if any
		if( focusedObject != null ) {
			camera.lookAt( focusedObject.getLocalTranslation(), new Vector3f( 0, 1, 0 ) );
			camera.getLocalRotation().normalize();
			camera.updateGeometricState( 0, true );
		}
	}
	
	/**
	 * Puts an action on the camera action queue
	 * @param action
	 */
	public void queueAction( CameraAction action ) {
		this.actionsQueue.add( action );
	}
	
	/**
	 * Sets the camera focus on the given node
	 * @param focusedObject The object to get the focus
	 */
	public void setFocusedObject( Node focusedObect) {
		this.focusedObject = focusedObect;
	}

	public CameraNode getCamera() {
		return camera;
	}

	/**
	 * @return The currently focused object or null, if there isn't any
	 */
	public Node getFocusedObject() {
		return focusedObject;
	}
	
	public boolean isIdle() {
		
		return this.actionsQueue.isEmpty() && this.currentAction == null;
	}
}
